controller: Handle UnicodeDecodeError from webob decoding invalid URLs
webob will try to utf-8 decode all %-encoded bytes in URL-parameters, but will not handle Unicode erors ... and neither did Kallithea. Visiting a URL like http://localhost:5000/?%AD would thus give an unhandled exception showing "Internal Server Error" to the user, and logging the full traceback and:
WebApp Error: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xad in position 0: invalid start byte
tests: address PytestDeprecationWarning for @pytest.yield_fixture
Adhere to the warning:
kallithea/tests/conftest.py:207: PytestDeprecationWarning: @pytest.yield_fixture is deprecated. Use @pytest.fixture instead; they are the same. @pytest.yield_fixture(scope="session")
setup: bump max versions of pip package dependencies
It is a bit risky to update versions on stable, but it is also risky to stay on old versions when there are better(?) options.
There are various reasons these max versions have been chosen. I have not analyzed problems seen when using higher versions, but the versions specified here seems like a safe progression of the broad baseline.
Latest pip version pip fail: WARNING: Ignoring version 5.0.5 of celery since it has invalid metadata: Requested celery<5.1,>=5 from .../celery-5.0.5-py3-none-any.whl (from Kallithea==0.7.0) has invalid metadata: Expected matching RIGHT_PARENTHESIS for LEFT_PARENTHESIS, after version specifier pytz (>dev) ~^ Please use pip<24.1 if you need to use this version.
We already use setuptools<67 for the same reason.
Pip will keep noting that a newer pip version is available. Resist the temptation to upgrade.
repo groups: make it possible to remove own explicit permissions, now when group owners always have admin permissions
Until recently, group owners very given explicit admin permissions on repo group, and special care was taken to make sure they didn't remove themselves.
Now we always give admin permissions to owners, and don't care about the explicit permissions. We no longer add them when creating groups or changing owner. There is no migration step to remove redundant permissions, but we should allow group admins to remove them. This change will thus remove the mechanism for preventing removal of own/owner permissions.
tests: skip reading Git system and global configuration in test_vcs_operations
The parent changeset reduced the dependency on global configuration and made it possible to run tests without any global git configuration. But it is still unfortunate to even look at the global configuration when running tests.
Global configuration is already disabled for Mercurial by setting HGRCPATH.
Now do something similar for Git. According to the git man page, GIT_CONFIG_GLOBAL and GIT_CONFIG_SYSTEM set to /dev/null will make Git skip reading the configuration files on all platforms.
Note that the GIT_CONFIG variables were introduced in Git 2.32.0, so this will not work with all the Git versions supported by Kallithea.
tests: stabilize Git committer in test_vcs_operations
Git tries to find out name and email in this order:
1. The author can be set e.g. via the `--author` option of `git commit`. 2. If set, the environment variables GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL are taken. 3. If set, various (global) config files are considered. 4. Unless disabled by the user.useconfigonly config, the names and emails are inferred from various system sources such as various fields from /etc/passwd, /etc/mailname and the environment variable EMAIL.
The author can be provided on the command line (1), but that is not possible for the committer.
It is not an option to modify Git’s configuration files, so the result of (3) depends on the system the tests run on, which should be avoided. A follow-up patch will try to instruct Git to not read the system Git configuration files.
(4) is also system-dependent. On some systems, (4) is disabled in the Git configuration. If enabled, Git will try to infer the committer name from the gecko field in /etc/passwd, but will fail if it is empty. The previous code passed the environment variable EMAIL to provide the corresponding email address.
By passing the names and emails via (2), we can set the author and committer name and email uniformly and prevent Git from using the system-dependent ways (3) and (4). This will replace the use of of EMAIL. The environment variables were introduced in 2005, so there should be no backwards compatibility problems.
The tests will specify --author explicitly in the cases where the actual name matters. We just need default values that can be used for committing when we don't care.
We set it as static defaults to: Author: test_regular <test_regular@example.com> Commit: test_admin <test_admin@example.com>
Based on changes and research by Manuel Jacob <me@manueljacob.de>.
The `packaging` vendored in setuptools cannot handle the broken syntax `Requires-Dist: pytz (>dev)` in venv/lib/python3.11/site-packages/celery-5.0.5.dist-info/METADATA .
The old celery version currently used by Kallithea is wrong, and setuptools has moved on after a reasonable grace period. We thus have to work around and avoid latest setuptools.
i18n: make sure 'en' in Accept-Language is recognized as having 100% coverage
The workaround in 7c7d6b5c07c7 no longer works after upstream addressed the main issue and released the changes in TurboGears 2.4.3 .
Setting `i18n.native = en` in the .ini works as a workaround.
The native language for translations is an implementation detail that users shouldn't have to configure, so we define it as a default value without making it explicit in the generated .ini template files.
Note that even though TG will figure out that languages like `en_US` should fall back to using the `en` `kallithea.mo`, it doesn't consider `en_US` native if `en` is in the native list but `en_US` isn't. We thus include the most common aliases for `en` in the list.
api: fix get_changeset() when incomplete raw_id is passed with with_reviews
Previously, ChangesetStatusModel was queried with the raw_id passed as an argument to the API function. When the raw_id was incomplete (i.e. shortened), no reviews were found. Using the full raw_id from the changeset instance fixes that.
Someone might argue that the caller is supposed to pass a full raw_id to the API function. However, in any case, the return value should not be incomplete without notice.
pullrequests: introduce limit to stop displaying additional changes
We've noticed some scalability issues when many descendants exist for the changesets in a pull request.
To resolve this issue, we instead do not display any additional changes at all if the amount of additional changes is larger than a configured limit.
(This occurred because we were merging a lot of heads in the repository.)
Throwing away some of the changesets would also keep the total amount more manageable, but this would result in an (for the user) unpredictable subset of changesets being shown.
This could be extended further with "too long to be shown - click here to show", but that was quite a bit of additional work and did not cover our use case of not allowing the display at all in case of too many additional changes.
After renaming a group, it would iterate over all the contained groups and repos and update their full path while logging the update from the/old/path to the the/new/path. Doing that, it would also visit the already renamed top level group, but since the full path of that one already had been updated, it would log it as renaming from the/new/path to the/new/path.
Fixed by logging when renaming in the first place, and skipping the top level repo group while iterating.
To avoid redundant logging, only log (and rename) if the name or parent actually change.
setup: use old importlib_metadata version to fix kombu failing on python < 3.8
Many libraries use the importlib_metadata library as fallback when running on Python versions older than 3.8 . For example setuptools when easy_install is used for install the Kallithea console_scripts entrypoints in the bin folder. The dependencies on importlib_metadata were indirect and without constrains on version number.
The problem is that Celery uses Kombu, which (on Python < 3.8) uses importlib_metadata in a way that is incompatible with importlib_metadata > 5.
Most obvious, building docs failed as: Running Sphinx v5.1.1
Configuration error: There is a programmable error in your configuration file:
Traceback (most recent call last): File ".../kallithea/venv/lib64/python3.7/site-packages/sphinx/config.py", line 347, in eval_config_file exec(code, namespace) File ".../kallithea/docs/conf.py", line 17, in <module> import kallithea File ".../kallithea/kallithea/__init__.py", line 45, in <module> CELERY_APP = celery.Celery() # needed at import time but is lazy and can be configured later File ".../kallithea/venv/lib64/python3.7/site-packages/celery/local.py", line 492, in __getattr__ [name]) File ".../kallithea/venv/lib64/python3.7/site-packages/celery/app/__init__.py", line 2, in <module> from celery import _state File ".../kallithea/venv/lib64/python3.7/site-packages/celery/_state.py", line 15, in <module> from celery.utils.threads import LocalStack File ".../kallithea/venv/lib64/python3.7/site-packages/celery/utils/__init__.py", line 16, in <module> from .nodenames import nodename, nodesplit, worker_direct File ".../kallithea/venv/lib64/python3.7/site-packages/celery/utils/nodenames.py", line 6, in <module> from kombu.entity import Exchange, Queue File ".../kallithea/venv/lib64/python3.7/site-packages/kombu/entity.py", line 7, in <module> from .serialization import prepare_accept_content File ".../kallithea/venv/lib64/python3.7/site-packages/kombu/serialization.py", line 440, in <module> for ep, args in entrypoints('kombu.serializers'): # pragma: no cover File ".../kallithea/venv/lib64/python3.7/site-packages/kombu/utils/compat.py", line 82, in entrypoints for ep in importlib_metadata.entry_points().get(namespace, []) AttributeError: 'EntryPoints' object has no attribute 'get'
That made readthedocs builds fail, when it in the default web configuration used Python 3.7 .
Fixed by introducing an explicit dependency on importlib_metadata < 5.
The repo group owner concept was only partially implemented. Owners were shown in the repo group listing, but couldn't be changed. Users owning repo groups couldn't be deleted, with no other solution than deleting owned repo groups.
This also fixes the existing broken update_repo_group API, which tried to use unimplemented functionality.
repo: introduce enable_downloads and enable_statistics when creating repos
These booleans were not shown in the normal repo creation form, so the form validation applied the "default" values of False. These values were however not used by the model when creating repos - it just unconditionally used the real global defaults.
The API already exposed some of this, but it wasn't implemented.
The web form for creating repos lacked these fields, but it was present in the repo edit form. Just make these fields mandatory. There will thus not be any defaults to apply in the model for creating repos.
Sphinx 3.0.4 doesn't version its dependencies correctly, and it fails with latest jinja 3.1.2: ImportError: cannot import name 'environmentfilter' from 'jinja2' (.../site-packages/jinja2/__init__.py)
Latest Sphinx version supports latest Jinja version and seems to render the documentation correctly.
070b8c39736f accidentally introduced a wrong assumption that url_scheme_variable is a bool. Fix to only check whether it has been set to something non-empty.
middleware: use config consistently in https_fixup
070b8c39736f did for unknown reasons introduce a use of the global kallithea.CONFIG . Instead, consistently use the application config object that has been passed.
Clicking "Add new" on /_admin/user_groups/1/edit/perms would flicker the input fields, and then show "User group permissions updated".
That turns out to be because HTML button tags default to 'submit' inside forms, and in this place (but not for user or repo group permissions) we didn't specify the button type as 'button'.
Deletion of a repository group that has a parent group (i.e. is not at the root of the repository group tree) failed as follows:
Traceback (most recent call last): [...] File ".../lib/python3.9/site-packages/tg/configurator/components/dispatch.py", line 114, in _call_controller return controller(*remainder, **params) File "<decorator-gen-5>", line 2, in delete
File "/home/tdescham/repo/contrib/kallithea/kallithea-release/kallithea/lib/auth.py", line 572, in __wrapper return func(*fargs, **fkwargs) File "/home/tdescham/repo/contrib/kallithea/kallithea-release/kallithea/controllers/admin/repo_groups.py", line 271, in delete if gr.parent_group: File ".../lib/python3.9/site-packages/sqlalchemy/orm/attributes.py", line 294, in __get__ return self.impl.get(instance_state(instance), dict_) File ".../lib/python3.9/site-packages/sqlalchemy/orm/attributes.py", line 730, in get value = self.callable_(state, passive) File ".../lib/python3.9/site-packages/sqlalchemy/orm/strategies.py", line 717, in _load_for_state raise orm_exc.DetachedInstanceError( sqlalchemy.orm.exc.DetachedInstanceError: Parent instance <RepoGroup at 0x7f1f2664f4c0> is not bound to a Session; lazy load operation of attribute 'parent_group' cannot proceed (Background on this error at: http://sqlalche.me/e/13/bhk3)
In the reference 'gr.parent_group', 'gr' is an SQLAlchemy object referring to the group being deleted, and 'gr.parent_group' is a lazy reference to its parent group. The 'lazy' means that the parent group object is not loaded automatically when 'gr' is assigned, but instead will be loaded on-the-fly when the parent group is actually accessed. See [1] and [2] for more information.
The problem was that the lazy 'parent_group' attribute was accessed _after_ deleting the database object it was part of.
Fix this by obtaining a handle to the parent group _before_ deleting the subgroup.
controllers: don’t pass start=0 to BaseRepository.get_changesets()
MercurialRepository.get_changesets() can fail if passing start=0 if the revision 0 is not in self.revisions. That can happen if revision 0 is not in the visible subset of the revisions in the repository. Before Kallithea changeset 7c43e15fb8bc7a73f17f577e59a4698589b6809d, it was working by chance because start=0 was treated like start=None in the relevant places (GitRepository.get_changesets still does that).
The intention of passing start=0 was seemingly to not limit the start. Therefore passing start=None (or nothing, as it’s the default value) should be correct.
I got the following traceback before this change:
Traceback (most recent call last): File "~/vcs/kallithea/kallithea/controllers/changelog.py", line 117, in index collection = c.db_repo_scm_instance.get_changesets(start=0, end=revision, File "~/vcs/kallithea/kallithea/lib/vcs/backends/hg/repository.py", line 529, in get_changesets start_pos = None if start is None else self.revisions.index(start_raw_id) ValueError: '4257f758b3eaacaebb6956d1aefc019afab956b8' is not in list
Running "kallithea-cli front-end-build" with npm 7.21.1 gave:
npm WARN old lockfile The package-lock.json file was created with an old version of npm, npm WARN old lockfile so supplemental metadata must be fetched from the registry. npm WARN old lockfile npm WARN old lockfile This is a one-time fix-up, please be patient...